
#include "lcd_internal.h"

#if !MODULE_CHECK_ENABLED( LCD_QSPI )
#error "must define qspi lcd interface!!!"
#endif

GUI_RAM_CODE
bool lcd_write_completed(void)
{
    if( lcd_wrctl.block_write ) 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.blocks.used ++;
            if( lcd_wrctl.blocks.used < lcd_wrctl.blocks.count )
            {
                // check next row 
                lcd_wrctl.pdata += lcd_wrctl.blocks.offset; // next block  
                lcd_wrctl.offset = 0; 
                uint16_t remain = lcd_wrctl.size;
                if( remain > LCD_XFER_MAX_SIZE )
                {
                    remain = LCD_XFER_MAX_SIZE; 
                }
                
                LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, remain );
                lcd_wrctl.offset = remain; //start a block 
            }
            else 
            {
                lcd_wrctl.isbusy = false; 
            }
        }
    }
    else 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.isbusy = false; 
        }
    }
    return lcd_wrctl.isbusy;
}



static void driver_init(void)
{
    LCD_SET_nRESET;
    LCD_DELAY_MS( 10 );
    LCD_SET_RESET;
    LCD_DELAY_MS( 20 );
    LCD_SET_nRESET;
    LCD_DELAY_MS( 20 );
#if 0// normal
    {
        lcd_qspi_write_cmd_para( 0xfe , NULL, 0 );
    }
    {
        lcd_qspi_write_cmd_para( 0xef , NULL, 0 );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x80 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x81 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x82 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x83 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x84 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x85 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x86 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x87 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x88 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x89 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x8a , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x8b , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x8c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x8d , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff}; 
        lcd_qspi_write_cmd_para( 0x8e , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xff};
        lcd_qspi_write_cmd_para( 0x8f , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x00}; 
        lcd_qspi_write_cmd_para( 0x36 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x05};
        lcd_qspi_write_cmd_para( 0x3a , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x77}; 
        lcd_qspi_write_cmd_para( 0xec , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x3e,0x00,0x00,0x00,0x00,}; 
        lcd_qspi_write_cmd_para( 0x74 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3e}; 
        lcd_qspi_write_cmd_para( 0x98 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3e}; 
        lcd_qspi_write_cmd_para( 0x99 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x18}; 
        lcd_qspi_write_cmd_para( 0x7e , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3f}; 
        lcd_qspi_write_cmd_para( 0xc3 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x10}; 
        lcd_qspi_write_cmd_para( 0xc4 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x04}; 
        lcd_qspi_write_cmd_para( 0xa1 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x04}; 
        lcd_qspi_write_cmd_para( 0xa2 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x1c}; 
        lcd_qspi_write_cmd_para( 0xa9 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x7e}; 
        lcd_qspi_write_cmd_para( 0xa8 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x40}; 
        lcd_qspi_write_cmd_para( 0xa7 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x73}; 
        lcd_qspi_write_cmd_para( 0xaf , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x44}; 
        lcd_qspi_write_cmd_para( 0xae , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38}; 
        lcd_qspi_write_cmd_para( 0xad , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x36}; 
        lcd_qspi_write_cmd_para( 0xa3 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x02}; 
        lcd_qspi_write_cmd_para( 0xc2 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x11}; 
        lcd_qspi_write_cmd_para( 0xc5 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x0e}; 
        lcd_qspi_write_cmd_para( 0xc6 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x13}; 
        lcd_qspi_write_cmd_para( 0xc7 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x0d}; 
        lcd_qspi_write_cmd_para( 0xc8 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x02}; 
        lcd_qspi_write_cmd_para( 0x70 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x02}; 
        lcd_qspi_write_cmd_para( 0xcb , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xb6,0x26}; 
        lcd_qspi_write_cmd_para( 0x7c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x24}; 
        lcd_qspi_write_cmd_para( 0xac , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x09,0x09}; 
        lcd_qspi_write_cmd_para( 0xb5 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x0b,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x60 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3a,0xe0,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x61 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x0d,0x72,0xdd,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x64 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x11,0x72,0xe1,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x65 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3b,0x08,0x08,0x00,0x08,0x29,0x5b}; 
        lcd_qspi_write_cmd_para( 0x68 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x88,0x04,0x88,0x84,0x88,0x04,0x50}; 
        lcd_qspi_write_cmd_para( 0x6c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x00,0x00,0x00,0x03,0x01,0x0f,0x0d,0x0b,0x09,0x16,
                          0x15,0x1d,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,
                          0x1d,0x15,0x16,0x0a,0x0c,0x0e,0x10,0x02,0x04,0x00,
                          0x00,0x00}; 
        lcd_qspi_write_cmd_para( 0x6e , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x45,0x09,0x08,0x08,0x26,0x2a}; 
        lcd_qspi_write_cmd_para( 0xf0 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x43,0x70,0x72,0x36,0x37,0x6f}; 
        lcd_qspi_write_cmd_para( 0xf1 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x45,0x09,0x08,0x08,0x26,0x2a}; 
        lcd_qspi_write_cmd_para( 0xf2 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x43,0x70,0x72,0x36,0x37,0x6f}; 
        lcd_qspi_write_cmd_para( 0xf3 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x00}; 
        lcd_qspi_write_cmd_para( 0x35 , data, sizeof(data) );
    }
#else //in order
    {
        lcd_qspi_write_cmd_para( 0xfe , NULL, 0 );
    }
    {
        lcd_qspi_write_cmd_para( 0xef , NULL, 0 );
    }
    {
        uint8_t data[] = {0x11}; 
        lcd_qspi_write_cmd_para( 0x80 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x70};
        lcd_qspi_write_cmd_para( 0x81 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x09}; 
        lcd_qspi_write_cmd_para( 0x82 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x03};
        lcd_qspi_write_cmd_para( 0x83 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x20};
        lcd_qspi_write_cmd_para( 0x84 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x10};
        lcd_qspi_write_cmd_para( 0x89 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x4f}; 
        lcd_qspi_write_cmd_para( 0x8a , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x59}; 
        lcd_qspi_write_cmd_para( 0x8c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x51};
        lcd_qspi_write_cmd_para( 0x8d , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x00}; 
        lcd_qspi_write_cmd_para( 0x36 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x05};
        lcd_qspi_write_cmd_para( 0x3a , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x77}; 
        lcd_qspi_write_cmd_para( 0xec , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x80,0x00,0x00,0x00,0x00,}; 
        lcd_qspi_write_cmd_para( 0x74 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3e}; 
        lcd_qspi_write_cmd_para( 0x98 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3e}; 
        lcd_qspi_write_cmd_para( 0x99 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3a}; 
        lcd_qspi_write_cmd_para( 0xc3 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x16}; 
        lcd_qspi_write_cmd_para( 0xc4 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x04}; 
        lcd_qspi_write_cmd_para( 0xa1 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x01,0x04}; 
        lcd_qspi_write_cmd_para( 0xa2 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x02}; 
        lcd_qspi_write_cmd_para( 0xcb , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xb6,0x26}; 
        lcd_qspi_write_cmd_para( 0x7c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x24}; 
        lcd_qspi_write_cmd_para( 0xac , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x80}; 
        lcd_qspi_write_cmd_para( 0xf6 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x09,0x09}; 
        lcd_qspi_write_cmd_para( 0xb5 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x0b,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x60 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3a,0xe0,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x63 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x0d,0x72,0xdd,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x64 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38,0x11,0x72,0xe1,0x5b,0x56}; 
        lcd_qspi_write_cmd_para( 0x66 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x3b,0x08,0x08,0x00,0x08,0x29,0x5b}; 
        lcd_qspi_write_cmd_para( 0x68 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x00,0x00,0x00,0x07,0x01,0x13,0x11,0x0b,0x09,0x16,
                          0x15,0x1d,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,
                          0x1d,0x15,0x16,0x0a,0x0c,0x12,0x14,0x02,0x08,0x00,
                          0x00,0x00}; 
        lcd_qspi_write_cmd_para( 0x6e , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x11}; 
        lcd_qspi_write_cmd_para( 0xbe , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0xcc,0x0c,0xcc,0x84,0xcc,0x04,0x50}; 
        lcd_qspi_write_cmd_para( 0x6c , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x72}; 
        lcd_qspi_write_cmd_para( 0x7d , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x38}; 
        lcd_qspi_write_cmd_para( 0x7e , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x02,0x03,0x09,0x05,0x0c,0x06,0x09,0x05,0x0c,0x06}; 
        lcd_qspi_write_cmd_para( 0x70 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x06,0x06,0x05,0x06};
        lcd_qspi_write_cmd_para( 0x90 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x45,0xff,0x00};
        lcd_qspi_write_cmd_para( 0x93 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x46,0x0b,0x0f,0x0a,0x10,0x3f}; 
        lcd_qspi_write_cmd_para( 0xf0 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x52,0x9a,0x4f,0x36,0x37,0xff}; 
        lcd_qspi_write_cmd_para( 0xf1 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x46,0x0b,0x0f,0x0a,0x10,0x3f}; 
        lcd_qspi_write_cmd_para( 0xf2 , data, sizeof(data) );
    }
    {
        uint8_t data[] = {0x52,0x9a,0x4f,0x36,0x37,0xff}; 
        lcd_qspi_write_cmd_para( 0xf3 , data, sizeof(data) );
    }
#endif
    {
        lcd_qspi_write_cmd_para( 0x11 , NULL, 0 );
    }
    LCD_DELAY_MS( 20 );
    {
        lcd_qspi_write_cmd_para( 0x29 , NULL, 0 );
    }
    LCD_DELAY_MS( 20 );
}

#define BIT_RFNE                                (0x00000001 << 3)
#define BIT_ADDR_PHASE_LENGTH(x)                ((x) & 0x00000003)
#define BIT_RD_DUMMY_LENGTH(x)                  (((x) & 0x00000fff))

bool em_lcd_qspi_read(uint16_t addr, uint16_t data_len, uint8_t *data)
{
    uint32_t rd_num = 0;
    SPIC2->ssienr = DISABLE;

    //set addr channel and data channel in ctrl0 register.
    SPIC2->ctrlr0 &= ~(BIT_CMD_CH(3) | BIT_ADDR_CH(3) | BIT_DATA_CH(3));

    //set RX mode in ctrl0 register in user mode.
    SPIC2->ctrlr0 |= BIT_TMOD(3);
    //spic_set_ctrl1(data_len);
    SPIC2->ctrlr1 = data_len;

    SPIC2->addr_length = BIT_ADDR_PHASE_LENGTH(3);
    //set dummy_cycle in autolen register[11:0]
    HAL_UPDATE32(&SPIC2->auto_length, 0xfff, BIT_RD_DUMMY_LENGTH(2));

    addr = addr << 8;
    SPIC2->dr[0].word = 0x03 | __REV(addr);

    SPIC2->ssienr = ENABLE;

    while (rd_num < data_len)
    {
        if (SPIC2->sr & BIT_RFNE)
        {
            data[rd_num++] = SPIC2->dr[0].byte;
        }
    }

    SPIC2->ssienr = DISABLE;

    return true;
}

void em_lcd_qspi_read_test(void)
{
    //Pad_Config(P4_3, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_DOWN, PAD_OUT_ENABLE, PAD_OUT_LOW);
    //lcd_qspi_cmd_param(0xFE, 0x00);//page switch
//    {
//        uint8_t data[] = {0x00}; 
//        lcd_qspi_write_cmd_para( 0xfe , data, sizeof(data) );
//    }
//    //lcd_qspi_write_cmd(0xF1);
//    {
//        uint8_t data[] = {0x00}; 
//        lcd_qspi_write_cmd_para( 0xf1 , data, sizeof(data) );
//    }
    uint8_t buf[6],bufda[6],bufdb[6],bufdc[6];
    em_lcd_qspi_read(0x04, 4, buf);
    DBG_DIRECT("[QSPI READ] %x - %x", buf[0], buf[1]);
    
    em_lcd_qspi_read(0xda, 2, bufda);
    DBG_DIRECT("[QSPI READ] %x - %x", bufda[0], bufda[1]);
    
    em_lcd_qspi_read(0xdb, 2, bufdb);
    DBG_DIRECT("[QSPI READ] %x - %x", bufdb[0], bufdb[1]);
    
    em_lcd_qspi_read(0xdc, 2, bufdc);
    DBG_DIRECT("[QSPI READ] %x - %x", bufdc[0], bufdc[1]);
    //Pad_Config(P4_3, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
    //while (1);
}

void em_lcd_init(void)
{
//    if( !is_initialized )
    {
//        is_initialized = true; 
        lcd_common_init();
        driver_init();
//        em_lcd_qspi_read_test();
//        lcd_qspi_clear(0,0,GUI_LCD_RES_H-1,GUI_LCD_RES_V-1,0x00F8);
    }
}

void em_lcd_power_off(void)
{
    lcd_qspi_write_cmd_para( 0x28 ,NULL,0); // turn off 
    LCD_DELAY_MS( 20 );
    lcd_qspi_write_cmd_para( 0x10 ,NULL,0); // sleep in 
    LCD_DELAY_MS( 20 );
    xDLPS_reset( lcd_dlps_index );
}

//void em_lcd_power_on(void)
//{
//    lcd_gdma_init();
//    lcd_qspi_write_cmd_para( 0x11 ,NULL,0); // sleep out 
//    LCD_DELAY_MS( 120 );
//    lcd_qspi_write_cmd_para( 0x29 ,NULL,0); // turn on 
//    LCD_DELAY_MS( 20 );
//}
void em_lcd_sleep_out(void)
{
    lcd_gdma_init();
    lcd_qspi_write_cmd_para( 0x11 ,NULL,0);
    LCD_DELAY_MS( 120 );
    xDLPS_set( lcd_dlps_index );
}
void em_lcd_turn_on(void)
{
    lcd_qspi_write_cmd_para( 0x29 ,NULL,0);
    LCD_DELAY_MS( 120 );
}
GUI_RAM_CODE
void em_lcd_set_window(int16_t x0, int16_t y0, int16_t w, int16_t h)
{
    uint16_t xstart = x0;
    uint16_t ystart = y0;
    uint16_t xend = xstart + w - 1;
    uint16_t yend = ystart + h - 1;
    uint8_t  data[4];

    data[0] = xstart >> 8;
    data[1] = xstart & 0xff;
    data[2] = xend >> 8;
    data[3] = xend & 0xff;
    lcd_qspi_write_cmd_para(0x2A,data,4);

    data[0] = ystart >> 8;
    data[1] = ystart & 0xff;
    data[2] = yend >> 8;
    data[3] = yend & 0xff;
    lcd_qspi_write_cmd_para(0x2B,data,4);

    lcd_qspi_enter_data_output_mode();
}

GUI_RAM_CODE
void em_lcd_write(uint8_t* p_buffer, uint32_t size)
{   
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy = true; 
    lcd_wrctl.block_write = false;
    lcd_wrctl.pdata = (uint8_t*)p_buffer;
    lcd_wrctl.offset = 0;
    lcd_wrctl.size = size;
    
    uint32_t chunk_remain = size; 
    if( chunk_remain > LCD_XFER_MAX_SIZE )
    {
        chunk_remain = LCD_XFER_MAX_SIZE; 
    }
    lcd_wrctl.offset = chunk_remain;
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
}

/*
    p_buffer -> LCD Memory 
    offset   -> next block offset 
    size     -> size of block  
    rows     -> block count 
*/
GUI_RAM_CODE
void em_lcd_write_block( uint8_t* p_buffer, int16_t offset, uint16_t size, int16_t count )
{
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy                = true;
    lcd_wrctl.block_write           = true; 
    lcd_wrctl.pdata                 = (uint8_t*)p_buffer;
    lcd_wrctl.offset                = 0; 
    lcd_wrctl.size                  = size; 
    
    lcd_wrctl.blocks.used           = 0;
    lcd_wrctl.blocks.size           = size;
    lcd_wrctl.blocks.count          = count;
    lcd_wrctl.blocks.offset         = offset;
    
    uint32_t chunk_remain = size; 
    if( chunk_remain > LCD_XFER_MAX_SIZE )
    {
        chunk_remain = LCD_XFER_MAX_SIZE; 
    }
    lcd_wrctl.offset                = chunk_remain; 
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
//    LOG_INFO1("[LCD]: block write count = %d", count );
}

void em_lcd_draw_point( int16_t x, int16_t y, uint16_t color )
{
//    em_lcd_set_window(x, y, 1, 1 );
//    LCD_SEND_DATA_ASYNC( (uint8_t*)&color, 2);
    int16_t x0 = x, y0 = y, w = 2, h = 2;
    uint16_t xstart = x0;
    uint16_t ystart = y0;
    uint16_t xend = xstart + w - 1;
    uint16_t yend = ystart + h - 1;
    uint8_t  data[14];

    data[0] = xstart >> 8;
    data[1] = xstart & 0xff;
    data[2] = xend >> 8;
    data[3] = xend & 0xff;
    lcd_qspi_write_cmd_para(0x2A,data,4);

    data[0] = ystart >> 8;
    data[1] = ystart & 0xff;
    data[2] = yend >> 8;
    data[3] = yend & 0xff;
    lcd_qspi_write_cmd_para(0x2B,data,4);

    data[0] = color >> 8;
    data[1] = color & 0xff;
    data[2] = color >> 8;
    data[3] = color & 0xff;
    data[4] = color >> 8;
    data[5] = color & 0xff;
    data[6] = color >> 8;
    data[7] = color & 0xff;
    lcd_qspi_write_cmd_para(0x2C,data,8);
}

void em_lcd_wait_transfer_completed(void)
{
    uint32_t timestamp=em_rtc_get_ticks();
    while( lcd_wrctl.isbusy && !em_rtc_check_time_expired( timestamp, EM_RTC_TOTICKS(500) ));
}

bool em_lcd_check_transfer_completed(void)
{
    return lcd_wrctl.isbusy; 
}

